package jnpf.util.excel;

import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.collect.ImmutableList;
import jnpf.enums.ImageEnum;
import jnpf.enums.ResourceEnum;
import jnpf.univer.data.resource.UniverDrawing;
import jnpf.univer.data.resource.UniverOffset;
import jnpf.univer.data.resource.UniverTransform;
import jnpf.univer.model.UniverWorkBook;
import jnpf.univer.resources.UniverResource;
import jnpf.univer.resources.UniverResourceData;
import jnpf.univer.sheet.*;
import jnpf.univer.style.*;
import jnpf.util.StringUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ：JNPF开发平台组
 * @version: V3.1.0
 * @copyright 引迈信息技术有限公司
 * @date ：2024/6/20 下午4:30
 */
public class UniverXSSFExcel extends ExcelParser {

    @Override
    public UniverWorkBook formFile(InputStream inputStream) throws IOException {
        XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
        UniverWorkBook univerWorkBook = new UniverWorkBook();
        univerWorkBook.setId(RandomUtil.randomString(10));
        univerWorkBook.setName("");
        Map<UniverStyle, String> styleMap = new HashMap<>();
        Map<String, UniverSheet> sheets = new HashMap<>();
        List<String> sheetOrder = new ArrayList<>();
        Map<String, UniverResourceData> drawingMap = new HashMap<>();
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            String sheetId = RandomUtil.randomString(10);
            sheetOrder.add(sheetId);
            XSSFSheet sheet = workbook.getSheetAt(i);
            UniverSheet univerSheet = new UniverSheet();
            univerSheet.setId(sheetId);
            univerSheet.setName(sheet.getSheetName());
            univerSheet.setHidden(!workbook.isSheetHidden(i) ? 0 : 1);
            univerSheet.setTabColor("");

            UniverSheetFreeze univerSheetFreeze = new UniverSheetFreeze();
            univerSheetFreeze.setXSplit(0);
            univerSheetFreeze.setYSplit(0);
            univerSheetFreeze.setStartRow(-1);
            univerSheetFreeze.setStartColumn(-1);
            univerSheet.setFreeze(univerSheetFreeze);

            Map<Integer, UniverSheetRowData> rowData = new HashMap<>();
            Map<Integer, UniverSheetColumnData> columnData = new HashMap<>();
            Map<Integer, Map<Integer, UniverSheetCellData>> cellData = new HashMap<>();
            for (int rowCount = 0; rowCount <= sheet.getLastRowNum(); rowCount++) {
                XSSFRow row = sheet.getRow(rowCount);
                Map<Integer, UniverSheetCellData> cells = new HashMap<>();
                if (null != row) {
                    for (int columnCount = 0; columnCount <= row.getLastCellNum(); columnCount++) {
                        XSSFCell cell = row.getCell(columnCount);
                        UniverSheetCellData univerSheetCellData = new UniverSheetCellData();
                        if (null != cell) {
                            //数据
                            Object value = "";
                            String formula = null;
                            CellType cellType = cell.getCellTypeEnum();
                            Integer type = null;
                            switch (cellType) {
                                case STRING:
                                    value = cell.getStringCellValue();
                                    type = 1;
                                    break;
                                case BOOLEAN:
                                    value = cell.getBooleanCellValue();
                                    type = 3;
                                    break;
                                case NUMERIC:
                                    value = cell.getNumericCellValue();
                                    type = 2;
                                    break;
                                case FORMULA:
                                    value = cell.getCellFormula();
                                    formula = "=" + value;
                                    type = 4;
                                    break;
                            }
                            univerSheetCellData.setV(value);
                            univerSheetCellData.setF(formula);
                            univerSheetCellData.setT(type);
                            //样式
                            XSSFCellStyle cellStyle = cell.getCellStyle();
                            UniverStyle style = getUniverStyle(cellStyle);
                            String styleName = styleMap.get(style) != null ? styleMap.get(style) : RandomUtil.randomString(6);
                            if (styleMap.get(style) == null) {
                                styleMap.put(style, styleName);
                            }
                            univerSheetCellData.setS(styleName);
                            cells.put(columnCount, univerSheetCellData);
                            UniverSheetColumnData univerSheetColumnData = new UniverSheetColumnData();
                            univerSheetColumnData.setHd(!sheet.isColumnHidden(columnCount) ? 0 : 1);
                            List<Integer> colHeight = new ArrayList<>();
                            colHeight.add(100);
                            colHeight.add((int) sheet.getColumnWidthInPixels(columnCount));
                            univerSheetColumnData.setW(Collections.max(colHeight));
                            columnData.put(columnCount, univerSheetColumnData);
                        }
                    }
                    cellData.put(rowCount, cells);
                    UniverSheetRowData univerSheetRowData = new UniverSheetRowData();
                    univerSheetRowData.setHd(!row.getZeroHeight() ? 0 : 1);
                    List<Integer> rowHeight = new ArrayList<>();
                    rowHeight.add(50);
                    rowHeight.add((int) row.getHeightInPoints());
                    univerSheetRowData.setH(Collections.max(rowHeight));
                    univerSheetRowData.setIa(0);
                    rowData.put(rowCount, univerSheetRowData);
                }
            }
            univerSheet.setCellData(cellData);
            univerSheet.setRowData(rowData);
            univerSheet.setColumnData(columnData);

            List<UniverSheetRange> mergeData = new ArrayList<>();
            for (CellRangeAddress region : sheet.getMergedRegions()) {
                UniverSheetRange univerSheetRange = new UniverSheetRange();
                univerSheetRange.setStartRow(region.getFirstRow());
                univerSheetRange.setStartColumn(region.getFirstColumn());
                univerSheetRange.setEndRow(region.getLastRow());
                univerSheetRange.setEndColumn(region.getLastColumn());
                mergeData.add(univerSheetRange);
            }
            univerSheet.setMergeData(mergeData);

            List<String> order = new ArrayList<>();
            Map<String, UniverDrawing> data = new HashMap<>();
            XSSFDrawing drawing = sheet.getDrawingPatriarch();
            if (drawing != null) {
                List<XSSFShape> shapes = drawing.getShapes();
                for (XSSFShape shape : shapes) {
                    if (shape instanceof XSSFPicture) {
                        XSSFPicture picture = (XSSFPicture) shape;
                        byte[] pictureData = picture.getPictureData().getData();
                        if (pictureData.length > 0) {
                            String drawingId = RandomUtil.randomString(10);
                            order.add(drawingId);
                            BufferedImage image = ImgUtil.toImage(pictureData);

                            UniverTransform sheetTransform = new UniverTransform();
                            XSSFClientAnchor anchor = picture.getClientAnchor();
                            UniverOffset univerFrom = new UniverOffset();
                            univerFrom.setRow(anchor.getRow1());
                            univerFrom.setColumn((int) anchor.getCol1());
                            univerFrom.setRowOffset(0);
                            univerFrom.setColumnOffset(0);
                            sheetTransform.setFrom(univerFrom);

                            UniverOffset univerTo = new UniverOffset();
                            univerTo.setRow(anchor.getRow2());
                            univerTo.setColumn((int) anchor.getCol2());
                            univerTo.setRowOffset(0);
                            univerTo.setColumnOffset(0);
                            sheetTransform.setTo(univerTo);

                            UniverDrawing univerDrawing = new UniverDrawing();
                            univerDrawing.setSheetTransform(sheetTransform);
                            univerDrawing.setDrawingType(0);
                            univerDrawing.setUnitId(univerWorkBook.getId());
                            univerDrawing.setSubUnitId(sheetId);
                            univerDrawing.setDrawingId(drawingId);
                            univerDrawing.setImageSourceType(ImageEnum.BASE64.name());
                            univerDrawing.setSource("data:image/png;base64," + ImgUtil.toBase64(image, "png"));
                            data.put(drawingId, univerDrawing);
                        }
                    }
                }
            }

            if (!order.isEmpty()) {
                UniverResourceData resourceData = new UniverResourceData();
                resourceData.setData(data);
                resourceData.setOrder(order);
                drawingMap.put(sheetId, resourceData);
            }

            UniverSheetRowHeader univerSheetRowHeader = new UniverSheetRowHeader();
            univerSheetRowHeader.setHidden(0);
            univerSheetRowHeader.setWidth(46);
            univerSheet.setRowHeader(univerSheetRowHeader);

            UniverSheetColumnHeader univerSheetColumnHeader = new UniverSheetColumnHeader();
            univerSheetColumnHeader.setHidden(0);
            univerSheetColumnHeader.setHeight(20);
            univerSheet.setColumnHeader(univerSheetColumnHeader);

            univerSheet.setZoomRatio(1);
            univerSheet.setScrollTop(0);
            univerSheet.setScrollLeft(0);
            univerSheet.setDefaultColumnWidth(88);
            univerSheet.setDefaultRowHeight(24);
            List<Integer> rowCount = new ArrayList<>();
            rowCount.add(100);
            rowCount.add(rowData.size());
            univerSheet.setRowCount(Collections.max(rowCount));
            List<Integer> columnCount = new ArrayList<>();
            columnCount.add(30);
            columnCount.add(columnData.size());
            univerSheet.setColumnCount(Collections.max(columnCount));
            univerSheet.setShowGridlines(sheet.isDisplayGridlines() ? 1 : 0);

            univerSheet.setSelections(ImmutableList.of("A1"));
            univerSheet.setRightToLeft(0);
            sheets.put(sheetId, univerSheet);
        }

        Map<String, UniverStyle> styles = styleMap.entrySet().stream().collect(Collectors.toMap(t -> t.getValue(), t -> t.getKey()));
        univerWorkBook.setStyles(styles);
        univerWorkBook.setSheetOrder(sheetOrder);
        univerWorkBook.setSheets(sheets);
        Map<String, String> resourceMap = new HashMap<>();
        if (!drawingMap.isEmpty()) {
            resourceMap.put(ResourceEnum.SHEET_DRAWING_PLUGIN.name(), JSONUtil.toJsonStr(drawingMap));
        }
        univerWorkBook.setResources(getUniverResources(resourceMap));
        return univerWorkBook;
    }

    private UniverStyle getUniverStyle(XSSFCellStyle cellStyle) {
        UniverStyle univerStyle = new UniverStyle();
        univerStyle.setHt((int) cellStyle.getAlignment().getCode());
        univerStyle.setVt((int) cellStyle.getVerticalAlignment().getCode());

        XSSFFont font = cellStyle.getFont();
        if (null != font) {
            univerStyle.setFf(font.getFontName());
            univerStyle.setFs((int) font.getFontHeightInPoints());
            univerStyle.setIt(font.getItalic() ? 1 : 0);
            univerStyle.setBl(font.getBold() ? 1 : 0);
            if (null != font.getXSSFColor()) {
                UniverStyleColor cl = new UniverStyleColor();
                cl.setRgb(rgb(font.getXSSFColor().getARGBHex()));
                univerStyle.setCl(cl);
            }
            if (Objects.equals(font.getUnderline(), Font.U_SINGLE)) {
                UniverStyleTextDecoration ul = new UniverStyleTextDecoration();
                ul.setS(1);
                univerStyle.setUl(ul);
            }
            if (font.getStrikeout()) {
                UniverStyleTextDecoration st = new UniverStyleTextDecoration();
                st.setS(1);
                univerStyle.setSt(st);
            }
        }
        if (null != cellStyle.getDataFormatString()) {
            UniverStylePattern pattern = new UniverStylePattern();
            pattern.setPattern(cellStyle.getDataFormatString());
            univerStyle.setN(pattern);
        }
        univerStyle.setBd(getUniverStyleBorder(cellStyle));

        XSSFColor bgColor = cellStyle.getFillForegroundColorColor();
        FillPatternType pattern = cellStyle.getFillPattern();
        if (null != bgColor && Objects.equals(pattern, FillPatternType.SOLID_FOREGROUND)) {
            UniverStyleColor background = new UniverStyleColor();
            background.setRgb(rgb(cellStyle.getFillForegroundColorColor().getARGBHex()));
            univerStyle.setBg(background);
        }

        UniverStyleTextRotation univerStyleTextRotation = new UniverStyleTextRotation();
        univerStyleTextRotation.setA(cellStyle.getRotation());
        univerStyle.setTr(univerStyleTextRotation);
        return univerStyle;
    }

    private String rgb(String colorStr) {
        String rgb = null;
        if (StringUtil.isNotEmpty(colorStr)) {
            rgb = "#" + colorStr.substring(2, 8);
        }
        return rgb;
    }

    private UniverStyleBorder getUniverStyleBorder(XSSFCellStyle cellStyle) {
        UniverStyleBorder univerStyleBorder = new UniverStyleBorder();
        int num = 0;
        if (null != cellStyle.getLeftBorderXSSFColor()) {
            UniverStyleBorderStyle left = new UniverStyleBorderStyle();
            UniverStyleColor leftColor = new UniverStyleColor();
            leftColor.setRgb(rgb(cellStyle.getLeftBorderXSSFColor().getARGBHex()));
            left.setCl(leftColor);
            univerStyleBorder.setL(left);
            num++;
        }
        if (null != cellStyle.getTopBorderXSSFColor()) {
            UniverStyleBorderStyle top = new UniverStyleBorderStyle();
            UniverStyleColor topColor = new UniverStyleColor();
            topColor.setRgb(rgb(cellStyle.getTopBorderXSSFColor().getARGBHex()));
            top.setCl(topColor);
            univerStyleBorder.setT(top);
            num++;
        }
        if (null != cellStyle.getRightBorderXSSFColor()) {
            UniverStyleBorderStyle right = new UniverStyleBorderStyle();
            UniverStyleColor rightColor = new UniverStyleColor();
            rightColor.setRgb(rgb(cellStyle.getRightBorderXSSFColor().getARGBHex()));
            right.setCl(rightColor);
            univerStyleBorder.setR(right);
            num++;
        }
        if (null != cellStyle.getBottomBorderXSSFColor()) {
            UniverStyleBorderStyle bottom = new UniverStyleBorderStyle();
            UniverStyleColor bottomColor = new UniverStyleColor();
            bottomColor.setRgb(rgb(cellStyle.getBottomBorderXSSFColor().getARGBHex()));
            bottom.setCl(bottomColor);
            univerStyleBorder.setB(bottom);
            num++;
        }
        return num > 0 ? univerStyleBorder : null;
    }

    private List<UniverResource> getUniverResources(Map<String, String> resourceMap) {
        List<UniverResource> resourcesList = new ArrayList<>();
        for (ResourceEnum resource : ResourceEnum.values()) {
            UniverResource model = new UniverResource();
            String name = resource.name();
            model.setName(name);
            model.setData(resourceMap.get(name) != null ? resourceMap.get(name) : "");
            resourcesList.add(model);
        }
        return resourcesList;
    }


}
